/**
 * @file rtk_heap.c
 * @author LokLiang (lokliang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-01
 *
 * @copyright Copyright (c) 2023
 *
 */

#include "prv_rtk_class.h"

#include <stdarg.h>

static void *_rtk_heap_malloc(void *heap_handle, va_list arp)
{
    size_t size = va_arg(arp, size_t);
    return heap_malloc(heap_handle, size);
}

static void *_rtk_heap_calloc(void *heap_handle, va_list arp)
{
    size_t size = va_arg(arp, size_t);
    return heap_calloc(heap_handle, size);
}

static void *_rtk_heap_malloc_tail(void *heap_handle, va_list arp)
{
    size_t size = va_arg(arp, size_t);
    return heap_malloc_tail(heap_handle, size);
}

static void *_rtk_heap_calloc_tail(void *heap_handle, va_list arp)
{
    size_t size = va_arg(arp, size_t);
    return heap_calloc_tail(heap_handle, size);
}

static void *_rtk_heap_realloc(void *heap_handle, va_list arp)
{
    size_t size = va_arg(arp, size_t);
    void *p = va_arg(arp, void *);

    return heap_realloc(heap_handle, p, size);
}

static void *_rtk_heapk_malloc(void *heap_handle, va_list arp)
{
    size_t size = va_arg(arp, size_t);
    void *key_base = va_arg(arp, void *);
    size_t key_size = va_arg(arp, size_t);

    return heapk_malloc(heap_handle, size, key_base, key_size);
}

/**
 * @brief 申请内存
 *
 * @param size
 * @return void*
 */
void *rtk_heap_malloc(size_t size, rtk_tick_t wait_ticks)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(wait_ticks);
    void *ret = _rtk_wait_memory(_rtk_heap_malloc, cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, &cm_rtk->heap_sem, wait_ticks, size);
    if (ret == NULL)
    {
        _RTK_WRN("Insufficient memory: size = %d", size);
    }
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 申请内存并置0
 *
 * @param size
 * @return void*
 */
void *rtk_heap_calloc(size_t size, rtk_tick_t wait_ticks)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(wait_ticks);
    void *ret = _rtk_wait_memory(_rtk_heap_calloc, cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, &cm_rtk->heap_sem, wait_ticks, size);
    if (ret == NULL)
    {
        _RTK_WRN("Insufficient memory: size = %d", size);
    }
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 申请内存；优先从空闲块的尾部申请
 *
 * @param size 申请的空间大小（字节）
 * @param wait_ticks 等待时间
 * @return void* 内存地址
 */
void *rtk_heap_malloc_tail(size_t size, rtk_tick_t wait_ticks)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(wait_ticks);
    void *ret = _rtk_wait_memory(_rtk_heap_malloc_tail, cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, &cm_rtk->heap_sem, wait_ticks, size);
    if (ret == NULL)
    {
        _RTK_WRN("Insufficient memory: size = %d", size);
    }
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 申请内存并置0；优先从空闲块的尾部申请
 *
 * @param size 申请的空间大小（字节）
 * @param wait_ticks 等待时间
 * @return void*
 */
void *rtk_heap_calloc_tail(size_t size, rtk_tick_t wait_ticks)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(wait_ticks);
    void *ret = _rtk_wait_memory(_rtk_heap_calloc_tail, cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, &cm_rtk->heap_sem, wait_ticks, size);
    if (ret == NULL)
    {
        _RTK_WRN("Insufficient memory: size = %d", size);
    }
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 重定义已申请的内存大小
 *
 * @param p
 * @param size
 * @return void*
 */
void *rtk_heap_realloc(void *p, size_t size, rtk_tick_t wait_ticks)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(wait_ticks);

    void *ret;
    cm_rtk->heap_log = p;
    if (p == NULL)
    {
        ret = _rtk_wait_memory(_rtk_heap_malloc, cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, &cm_rtk->heap_sem, wait_ticks, size);
    }
    else
    {
        ret = _rtk_wait_memory(_rtk_heap_realloc, cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, &cm_rtk->heap_sem, wait_ticks, size, p);
    }
    if (ret == NULL)
    {
        _RTK_WRN("Insufficient memory: size = %d", size);
    }
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 释放内存
 *
 * @param p
 */
void rtk_heap_free(void *p)
{
    if (p)
    {
        _RTK_TRACE_ENTRY();
        _RTK_CHECK_ISR();
        _RTK_CHECK_HEAP(p);

        heap_free(cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, p);

        _rtk_sem_release(&cm_rtk->heap_sem);

        _RTK_TRACE_EXIT();
    }
}

/**
 * @brief 获取内存指针是否有效
 *
 * @param p
 * @return true
 * @return false
 */
bool rtk_heap_is_valid(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    bool ret = heap_is_valid(cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 已申请内存块的实际占用空间大小（不含所有控制信息）（字节）
 *
 * @param p
 * @return size_t
 */
size_t rtk_heap_block_size(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    size_t ret = heap_block_size(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 已申请内存块的实际占用空间大小（含所有控制信息）（字节）
 *
 * @param p
 * @return size_t
 */
size_t rtk_heap_space_size(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    size_t ret = heap_space_size(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 获取总已使用空间
 *
 * @return size_t
 */
size_t rtk_heap_used_size(void)
{
    _RTK_TRACE_ENTRY();
    size_t ret = heap_used_size(cm_rtk != NULL ? &cm_rtk->heap_handle : NULL);
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 获取总空闲空间（包含所有碎片）
 *
 * @return size_t
 */
size_t rtk_heap_free_size(void)
{
    _RTK_TRACE_ENTRY();
    size_t ret = heap_free_size(cm_rtk != NULL ? &cm_rtk->heap_handle : NULL);
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 获取当前最大的连续空间
 *
 * @return size_t
 */
size_t rtk_heap_block_max(void)
{
    _RTK_TRACE_ENTRY();
    size_t ret = heap_block_max(cm_rtk != NULL ? &cm_rtk->heap_handle : NULL);
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 获取堆空间信息
 *
 * @param dst_used[out] 已用空间（字节）
 * @param dst_free[out] 总空闲空间（字节）
 * @param dst_max_block[out] 最连续的空闲空间（字节）
 * @return rtk_err_t
 */
rtk_err_t rtk_heap_info(size_t *dst_used, size_t *dst_free, size_t *dst_max_block)
{
    _RTK_TRACE_ENTRY();
    int ret = heap_info(cm_rtk != NULL ? &cm_rtk->heap_handle : NULL, dst_used, dst_free, dst_max_block);
    _RTK_TRACE_EXIT();

    if (ret == 0)
    {
        return RTK_OK;
    }
    else
    {
        return RTK_FAIL;
    }
}

/**
 * @brief 在散列表中申请一个带映射键值的内存
 *
 * @param mem_size
 * @param key_base
 * @param key_size
 * @param wait_tick
 * @return void*
 */
void *rtk_heapk_malloc(size_t mem_size, const void *key_base, uint8_t key_size, rtk_tick_t wait_ticks)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(wait_ticks);
    void *ret = _rtk_wait_memory(_rtk_heapk_malloc, &cm_rtk->heapk_handle, &cm_rtk->heap_sem, wait_ticks, mem_size, key_base, key_size);
    if (ret == NULL)
    {
        _RTK_WRN("Insufficient memory: mem_size = %d, key_size = %d", mem_size, key_size);
    }
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 只删除关键字，但所申请的内存依然保留并可用
 *
 * @param p
 */
void rtk_heapk_clr_key(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    heapk_clr_key(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
}

/**
 * @brief 由 heapk_CreateTab() 所申请获得的指针
 *
 * @param p
 */
rtk_err_t rtk_heapk_free(void *p)
{
    if (p == NULL)
    {
        return RTK_E_PARAM;
    }

    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();
    _RTK_CHECK_HEAPK(p);

    heapk_free(p);
    _rtk_sem_release(&cm_rtk->heap_sem);

    _RTK_TRACE_EXIT();
    return RTK_OK;
}

/**
 * @brief 重置列举指针
 */
void rtk_heapk_list_reset(void)
{
    _RTK_TRACE_ENTRY();
    heapk_list_reset(&cm_rtk->heapk_handle);
    _RTK_TRACE_EXIT();
}

/**
 * @brief 列举下个已申请的内存信息
 *
 * @param store_mem_base
 * @param store_key_base
 * @param store_key_size
 * @return true
 * @return false
 */
bool rtk_heapk_list_next(void **store_mem_base, void **store_key_base, uint8_t *store_key_size)
{
    _RTK_TRACE_ENTRY();
    bool ret = heapk_list_next(&cm_rtk->heapk_handle, store_mem_base, store_key_base, store_key_size);
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 获取内存指针是否有效
 *
 * @param p
 * @return true
 * @return false
 */
bool rtk_heapk_is_valid(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    bool ret = heapk_is_valid(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 通过键值查找 heapk_malloc() 的申请的内存地址
 *
 * @param key_base
 * @param key_size
 * @return void*
 */
void *rtk_heapk_block_base(const void *key_base, uint8_t key_size)
{
    _RTK_TRACE_ENTRY();
    void *ret = heapk_block_base(&cm_rtk->heapk_handle, key_base, key_size);
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 通过内存封装地址获取 heapk_malloc() 申请时设定的内存大小
 *
 * @param p
 * @return size_t
 */
size_t rtk_heapk_block_size(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    size_t ret = heapk_block_size(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 已申请内存块的实际占用空间大小（含所有控制信息）（字节）
 *
 * @param p
 * @return size_t
 */
size_t rtk_heapk_space_size(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    size_t ret = heapk_space_size(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 通过内存封装地址获取 heapk_malloc() 申请时设定的键值地址
 *
 * @param p
 * @return void*
 */
void *rtk_heapk_key_base(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    void *ret = heapk_key_base(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}

/**
 * @brief 通过内存封装地址获取 heapk_malloc() 申请时设定的键值的有效字节数
 *
 * @param p
 * @return size_t
 */
size_t rtk_heapk_key_size(void *p)
{
    _RTK_TRACE_ENTRY();
    cm_rtk->heap_log = p;
    size_t ret = heapk_key_size(p);
    cm_rtk->heap_log = NULL;
    _RTK_TRACE_EXIT();
    return ret;
}
